home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / comm / revrdist.sit / RevRdist / RevRdist src / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-18  |  5.8 KB  |  222 lines  |  [TEXT/KAHL]

  1. /*
  2.  * dispatch.c - routines concerned with allowing the running part of
  3.  *    the application be "event-driven," even though there are normally
  4.  *    no events to process.
  5.  *    Put another way, these routines make it easier for the routines
  6.  *    which take a long time to run to drop back and check for user
  7.  *    events, without each one having to be able to handle all the
  8.  *    possible events.
  9.  *
  10.  *    The routines allow routines to pass argument lists to called
  11.  *    routines, and for the called routines to return values to their
  12.  *    callers, but such values must be copied to heap storage if they
  13.  *    need to be retained past the initial call or return.
  14.  *
  15.  *    Dispatched routines are passed a handle to a frame_t which they
  16.  *    can resize to use for per-instance local storage.  This handle
  17.  *    is locked before each call, except for the initial call to an
  18.  *    instance (since the routine is going to resize it immediately).
  19.  *    The handle is unlocked when the routine returns.
  20.  *
  21.  *    The frames of routines which pushCall another routine remain
  22.  *    locked until the calling routine returns after being popCalled
  23.  *    back to.
  24.  */
  25.  
  26. #include "RevRdist.h"
  27. #include "dispatch.h"
  28. #include <TransSkelProto.h>
  29.  
  30.  
  31. static    frameHdl    CallStack = 0;
  32. static    short        Request = R_CONT;
  33.  
  34. /*
  35.  *=========================================================================
  36.  * dispatch() - TransSkel background routine which takes care of
  37.  *        calling the real routines to get work done.
  38.  * entry:    idle() must have been pushCall()ed
  39.  *=========================================================================
  40.  */
  41. void
  42. dispatch ()
  43. {
  44.     short        result;
  45.     Longint        start;
  46.  
  47.     if (!CallStack)
  48.     {
  49.         /*
  50.          * The routine stack is empty!  We are in deep trouble.
  51.          */
  52.         Clue0 = (SP) "\pdispatch";
  53.         Clue1 = (SP) "\pCallStack";
  54.         Clue2 = (SP) "\pinternal error";
  55.         panic (true, E_SYS, nil);
  56.         SkelBackground (nil);
  57.         SkelWhoa ();
  58.         return;
  59.     }
  60.     if (Pause == S_PAUSED)
  61.         return;
  62.     for (start = TickCount (); start == TickCount (); )
  63.     {
  64.         HLock ((Handle)CallStack);
  65.         result = (*(*CallStack)->proc) (CallStack, Request, nil);
  66.         if (CallStack)
  67.             HUnlock ((Handle)CallStack);
  68.         switch (result)
  69.         {
  70.         case R_CONT:
  71.             /*
  72.              * Current procedure wishes to be recalled.
  73.              */
  74.             Request = result;
  75.             break;
  76.     
  77.         case R_ERROR:
  78.             /*
  79.              * Procedure detected a system error.
  80.              * ALERT the user and then start a BACKOUT or QUIT based on the
  81.              * response.
  82.              * The procedure is responsible for setting ClueID, Clue0, and
  83.              * Clue1
  84.              */
  85.             Request = R_BACKOUT;
  86.             panic (false, E_SYS, nil);
  87.             if (Quit)
  88.                 Request = R_QUIT;
  89.             break;
  90.     
  91.         case R_BACKOUT:
  92.         case R_QUIT:
  93.             if (result > Request)
  94.                 Request = result;        /* possibly increase seriousness */
  95.             break;
  96.         }
  97.     }
  98. }
  99.  
  100. /*
  101.  *=========================================================================
  102.  * pushCall (p, ap) - push call to dispatched routine
  103.  * entry:    p = Routine to call
  104.  *            ap = Ptr to argument list
  105.  * returns:    result of R_INIT call to routine
  106.  *            else R_ERROR if cannot get memory
  107.  *=========================================================================
  108.  */
  109. Integer
  110. pushCall (p, ap)
  111.     dispProcPtr    p;
  112.     Ptr *        ap;
  113. {
  114. register framePtr        f;
  115.     frameHdl            h;
  116.     frameHdl            oldstack;
  117.     short                result;
  118.  
  119.     if (Watch)
  120.         SetCursor (*Watch);
  121.     oldstack = CallStack;
  122.     h = (frameHdl) NewHandle (sizeof (frame_t) );
  123.     if (h == nil)
  124.     {
  125.         if ((ClueID = ResError()) == 0)
  126.             ClueID = memFullErr;
  127.         Clue0 = (SP) "\ppushCall";
  128.         Clue1 = (SP) "\pNewHandle";
  129.         return R_ERROR;
  130.     }
  131.     f = *h;
  132.     /*
  133.      * Link frame into stack and call routine
  134.      */
  135.     f->proc = p;
  136.     f->state = 0;
  137.     f->link = CallStack;
  138.     CallStack = h;
  139.     /*
  140.      * At this point, the callee's frameHdl is not locked, but the
  141.      * caller's probably still is from when it was dispatch()ed.
  142.      */
  143.     result = (*p) (h, (short) R_INIT, ap);
  144.     if (result != R_CONT)
  145.     {
  146.         CallStack = oldstack;
  147.         DisposHandle ((Handle) h);
  148.     }
  149.     else
  150.         MoveHHi ((Handle) h);    /* since it spends a lot of time locked */
  151.     return result;
  152. }
  153.  
  154.  
  155. /*
  156.  *=========================================================================
  157.  * popCall (request, rp) - pop frame off dispatch stack and restart
  158.  *        nested routine
  159.  * entry:    request = request parameter for uncovered routine (R_CONT)
  160.  *            rp = return parameter for uncovered routine
  161.  * returns:    result of call to uncovered routine, but
  162.  * WARNING: the dispatch frame for the caller of popCall is gone when popCall
  163.  *            returns, which means popCall should almost always be called like:
  164.  *                return (popCall (...));
  165.  *=========================================================================
  166.  */
  167. Integer
  168. popCall (request, rp)
  169.     short            request;
  170.     Ptr *            rp;
  171. {
  172. register frameHdl    h;
  173. register frameHdl    oldstack;
  174.     short            result;
  175.  
  176.     oldstack = CallStack;
  177.     CallStack = h = (*oldstack)->link;
  178.     HLock ((Handle)h);
  179.     /*
  180.      * Note that for the duration of this first call to the resumed
  181.      * routine, the exiting routine's automatic variables and dispatch
  182.      * frame are still available.
  183.      */
  184.     result = ((*(*h)->proc) (h, request, rp));
  185.     /*
  186.      * When popCall returns to the pop'er, the pop'er's stack frame is
  187.      * gone and must not be referenced.
  188.      */
  189.     HUnlock ((Handle)oldstack);
  190.     DisposHandle ((Handle)oldstack);
  191.     return result;
  192. }
  193.  
  194.  
  195.  
  196. /*
  197.  *=========================================================================
  198.  * resizeFrame (fh, n) - grow a basic frame up to a larger size
  199.  * entry:    fh = handle to frame
  200.  *            n = total size, in bytes, needed for local memory
  201.  * returns:    0 on success, added space has been zeroed
  202.  *            <> is OSErr
  203.  *=========================================================================
  204.  */
  205. OSErr
  206. resizeFrame (fh, n)
  207.     register frameHdl    fh;
  208.     register Size        n;
  209. {
  210.     register Size        cur;
  211.     register OSErr        error;
  212.     register Ptr        p;
  213.  
  214.     if (n < sizeof (frame_t))
  215.         return paramErr;
  216.     SetHandleSize ((Handle) fh, n);
  217.     if (error = MemError ())
  218.         return error;
  219.     for (p = *(Handle)fh + sizeof (frame_t), n -= sizeof (frame_t); n; n--)
  220.         *p++ = 0;
  221.     return 0;
  222. }